package applet.molecule;

import java.util.ArrayList;
import java.util.List;

import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;

import applet.molecule.Atom;

/**
 * 
 * Class Attribute keeps a record of all information for displaying atoms in the 3D world.
 * 
 * This class should be declared and inited before creating 3D universes.
 * 
 */

public class Attribute {

	/**	The global coordinate of center point of the whole scene */
	private Point3d center;

	/**
	 *	The global coordinate of original point in local coordinate
	 */
	private Vector3d translate;

	/**	The radius of the scene */
	private double sceneRadius;

	/**	The radius of the axis */
	private float axisRadius;

	/**	The color of the directional light */
	private Color3f lightColor;

	/**	The direction of the light in local system */
	private Vector3f lightDirection;

	/**	The background color */
	private Color3f bgColor;

	/**	radiuses of H, N, O */
	private float sphereRadiusH;
	private float sphereRadiusN;
	private float sphereRadiusO;

	/**	radius of carbochain  */
	private float pipeRadiusC;
	
	/**
	 * two carbon atoms should be connectted if distance between them is less
	 * than pipeThresC
	 */
	public static final float PIPE_THRES_C = 2.0f;
	private float pipeThresCX = 0.0f;

	/**	colors of different atoms */
	private Color3f blueSphereColor;
	private Color3f redSphereColor;
	private Color3f greenSphereColor;
	private Color3f whiteSphereColor;

	/**	whether the carbon atoms should be displayed */
	private boolean isCBall;
	
	private boolean axisVisible;

	/**	whether the carbochains should be connected with other kind of atoms */
	private boolean needCX;

	/**	controling the view port */
	private double backClipDis;
	private double frontClipDis;

	/**	information about atoms */
	private List<Atom> atomList;

	/**
	 *	init member vars with default values
	 */
	public Attribute() {
		center = new Point3d(0.0f, 0.0f, 0.0f);
		sceneRadius = 0.0f;
		axisRadius = 0.05f;
		translate = new Vector3d(0.0f, 0.0f, -10.0f);

		lightColor = new Color3f(0.8f, 0.8f, 0.8f);
		lightDirection = new Vector3f(4.0f, -7.0f, -12.0f);

		bgColor = new Color3f(0.4f, 0.4f, 0.4f);

		sphereRadiusO = 0.8f;	// standard sceneRadius
		sphereRadiusH = 0.574f;
		sphereRadiusN = 0.816f;
		pipeRadiusC = 0.1f;
		pipeThresCX = 1.5f; //	carbon atoms and other atoms should connectted if distance between them is less than pipeThresCX

		blueSphereColor = new Color3f(0.0f, 0.0f, 0.9f);
		redSphereColor = new Color3f(0.9f, 0.0f, 0.0f);
		greenSphereColor = new Color3f(0.0f, 0.9f, 0.0f);
		whiteSphereColor = new Color3f(0.9f, 0.9f, 0.9f);

		backClipDis = 100.0;
		frontClipDis = 0.001;
		
		axisVisible = false;
		isCBall = false;
		needCX = true;
	}
	
	public void setAxisVisible(boolean visible){
		axisVisible = visible;
	}
	
	public boolean isAxisVisible(){
		return axisVisible;
	}
	
	public float getAxisRadius(){
		return axisRadius;
	}

	/**
	 * Set information of atoms to display
	 * 
	 * @param list information of atoms to display. They could be get from the user-uploaded file.
	 * 
	 */
	public void initParams(List<Atom> list) {
		atomList = new ArrayList<Atom>();
		
		int num = list.size();

		center.x = 0.0;
		center.y = 0.0;
		center.z = 0.0;

		for (Atom a: list) {
			center.x += a.x;
			center.y += a.y;
			center.z += a.z;
		}

		if (num > 0) {
			center.x /= num;
			center.y /= num;
			center.z /= num;
		}

		float x, y, z;
		for (Atom a: list) {
			x = a.x - (float) center.x;
			y = a.y - (float) center.y;
			z = a.z - (float) center.z;

			atomList.add(new Atom(a.element, x, y, z));

			//	get the sceneRadius of the scene bounding sphere
			double temp = Math.sqrt(x * x + y * y + z * z);
			if (temp > sceneRadius) {
				sceneRadius = temp;
				axisRadius = (float)(sceneRadius/90);
			}
		}

		sceneRadius *= 2;

		//	set a proper postion of the view port
		translate.x = 0;
		translate.y = 0;
		translate.z = -sceneRadius;
	}

	/**
	 * Get the number of atoms to display.
	 */
	public int getBallCount() {
		return atomList.size();
	}

	/**
	 * Get information about a certain atom
	 */
	public Atom getBallParas(int Index) {
		return atomList.get(Index);
	}

	/**
	 * Get center of the scene before translation.
	 */
	public Point3d getSceneCenterLocal() {
		return center;
	}

	/**
	 * Get center of the scene in global system.
	 */
	public Vector3d getSceneCenterGlobal() {
		return translate;
	}

	/**
	 * Get radius of the scene
	 */
	public double getSceneRadius() {
		return sceneRadius;
	}

	/**
	 * Get color of the directional lights
	 */
	public Color3f getDLightColor() {
		return lightColor;
	}

	/**
	 * Get direction of the directional light
	 */
	public Vector3f getDLightDirection() {
		return lightDirection;
	}

	/**
	 * Get the background color
	 */
	public Color3f getBGColor() {
		return bgColor;
	}

	/**
	 * Get radius of a certain kind of atoms
	 * 
	 * @param sphereType a certain type of atoms
	 * 
	 * @retrun -1 if the type is invalid
	 * 
	 */
	public float getSphereRadius(String sphereType) {
		if (sphereType.equals("C"))
			return pipeRadiusC;

		if (sphereType.equals("H"))
			return sphereRadiusH;

		if (sphereType.equals("N"))
			return sphereRadiusN;

		if (sphereType.equals("WO") || sphereType.equals("HO"))
			return sphereRadiusO;

		return -1.0f;
	}

	/**
	 * Get the color vector of green
	 */
	public Color3f getColorGreen() {
		return greenSphereColor;
	}

	/**
	 * Get the color vector of white
	 */
	public Color3f getColorWhite() {
		return whiteSphereColor;
	}

	/**
	 * Get the color vector of blue
	 */
	public Color3f getColorBlue() {
		return blueSphereColor;
	}

	/**
	 * Get the color vector of red
	 */
	public Color3f getColorRed() {
		return redSphereColor;
	}

	/**
	 * Get the back clip distance
	 */
	public double GetBCDis() {
		return backClipDis;
	}

	/**
	 * Get the front clip distance
	 */
	public double GetFCDis() {
		return frontClipDis;
	}

	/**
	 * Get the coordinate of center in x-axis
	 */
	public float getCenterX() {
		return (float) center.x;
	}

	/**
	 * Get the coordinate of center in y-axis
	 */
	public float getCenterY() {
		return (float) center.y;
	}

	/**
	 * Get the coordinate of center in z-axis
	 */
	public float getCenterZ() {
		return (float) center.z;
	}

	/**
	 * Get the PipeThresCX
	 */
	public float getPipeThresCX() {
		return pipeThresCX;
	}

	/**
	 * Get the radius of carbochains
	 */
	public float getPipeRadiusC() {
		return pipeRadiusC;
	}

	/**
	 * Whether carbon atoms should be displayed
	 */
	public boolean isCBall() {
		return isCBall;
	}

	/**
	 * Whether carboChains should be connected with other kind of atoms
	 */
	public boolean needCX() {
		return needCX;
	}
}
